#include <mips/regdef.h>
#include <sys/syscall.h>

.text
.align 2
.globl encode
.ent encode

encode:
	.frame $fp, 52, ra
	.set noreorder
	.cpload t9
	.set reorder

	#cargo stack frame...
	subu sp, sp, 52


	# Save Register Area
	.cprestore 40 # equivale a... sw gp, 40($sp)
	sw ra, 48(sp)
	sw $fp, 44(sp)
	move $fp, sp

	# Local & Temporal Area
	sw a0, 8(sp)       # input file descriptor
	sw a1, 12(sp)      # output file descriptor
    	sb $0, 16(sp)      # char para leer
    	sw $0, 20(sp)      # buffer hexa
	#sw $0, 32(sp)      # retorno de la función

while:
	lw a0, 8(sp)	   #cargo la dirección de iput
	la a1, 16(sp)      #guardo direccion donde se escribe el char
    	li a2, 1           #cantidad de bytes a leer
    	li v0, SYS_read    #cargo syscall
    	syscall            #ejecuto syscall

	#################################
	bltz	v0, error_read_encode 	# Terminar si error
	#################################

    	beq v0,$0, finalizar_encode_ok   #si es cero, ejecuto END

    	la a0, 20(sp)                 #cargo direccion buffer
    	lb a1, 16(sp)                 #cargo caracter
    	jal d

    	lw a0, 12(sp)                 #cargo en a0 la salida
    	la a1, 20($fp)                #cargo en a1 direccion del buffer
    	li a2, 2                      #cantidad de caracteres a escribir
    	li v0,SYS_write
    	syscall
	#################################
	bltz	v0, error_write_encode 	# Terminar si no escribo la cantidad pedida (< 1)
	#################################
    	b while                       	#vuelve a while

finalizar_encode_ok:
	li v0, 0
	b finalizar_encode

error_read_encode:
	li v0, 1
	b finalizar_encode 

error_write_encode:
	li v0, 2
	b finalizar_encode 

finalizar_encode:
	move sp, $fp
	lw $fp, 44(sp) # frame pointer
	lw gp, 40(sp) # global pointer
	lw ra, 48(sp)   # levanto return address
	addu sp,sp,52 # destruyo stack frame
    	j ra
.end encode

.ent d
d:
	.frame $fp, 32, ra
	.set noreorder
	.cpload t9
	.set reorder

	#cargo stack frame...
	subu sp, sp, 32

	# Save Register Area
	.cprestore 20 
	sw ra, 28(sp)
	sw $fp, 24(sp)
	move $fp, sp

	# Local & Temporal Area
	sw a0, 0(sp) #	unsigned char* vector 
	sw a1, 4(sp) # 	uint8_t value
	sll t2, a1, 24 # uint8_t aux = value << 4
	srl t2, t2, 28 # uint8_t less_sing = aux >> 4
	sll t3, a1, 28 
	srl t3, t3, 28 # uint8_t most_sing = value >> 4
	sll t2, t2, 2 # multiplico por 4
	sll t3, t3, 2 # multiplico por 4
	la t4, vector # vector_converter[0]
	addu t5, t4, t2 # &(vector_converter[0] + less_sing)
	lb t6, 0(t5) # vector_converter[0] + less_sing
	addu t5, t4, t3 # &(vector_converter[0] + most_sing)
	lb t7, 0(t5) # vector_converter[0] + most_sing
	sb t6, 0(a0) # vector[0] = vector_converter[most_sing]
	sb t7, 1(a0) # vector[1] = vector_converter[less_sing]
	sb zero, 2(a0) # vector[2] = '\0'
	b finalizar_d


finalizar_d:
	move sp, $fp	
	lw $fp, 24(sp) # frame pointer
	lw gp, 20(sp) # global pointer
	lw ra, 28(sp)   # levanto return address
	addu sp,sp,32 # destruyo stack frame
	j ra
.end d

.globl decode
.ent decode

decode:
        .frame  $fp,52,ra
        .set    noreorder
        .cpload t9
        .set    reorder
        subu    sp,sp,52
        .cprestore 24
                                #   Save Register Area
                                # 36| ////PADDING//// |
        sw      ra,32(sp)     	# 32|       ra        |
        sw      $fp,28(sp)     # 28|       fp        |
        move    $fp,sp
        sw      a0,40(sp)      # a0: infd
        sw      a1,44(sp)      # a1: outfd
        sw      $0,48(sp)      # par_hexa
        sw      $0,16(sp)      # Guardo indice_par_hexa inicial para return
E_WHILE:
        lw      t0,48(sp)      # t0 <-- indice_par_hexa
        li      t1,1            # t1 <-- 1
 
       # blt     t0,t1,E_DO      # (indice_par_hexa < 1) ? => E_DO
       # b       finalizar_decode_ok  # (indice_par_hexa >= 1) ? => E_FIN
E_DO:
        #lw     a0,40(sp)      # arg1: infd
        #lw     a1,44(sp)      # arg2: outfd
        move    a2,t0		# arg3: indice_par_hexa (modificado)
        la      a3,16(sp)      # arg4: direccion par_hexa
        la      t9,f           	# Cargo direccion de f(...)
        jal     ra,t9         	# Llamo f(arg1,arg2,arg3,arg4)
        sw      v0,48(sp)      # Guardo el resultado indice_par_hexa para return
	
	#################################
	beq	v0, -1, finalizar_decode_error_read 	# Terminar si error en read
	#################################


	#################################
	beq	v0, -2, finalizar_decode_error_write 	# Terminar si error en write
	#################################

	#################################
	beq	v0, 0,	finalizar_decode_ok 	# Terminar si error en write
	#################################



        b       E_WHILE


E_FIN:
        lw      v0,48(sp)      # recupero valor return en v0
        lw      ra,32(sp)     	# Recupero ra
        lw      $fp,28(sp)     # Recupero fp
        lw      gp,24(sp)     	# Recupero gp
        addu    sp,sp,52      # Destruyo stack
        j       ra             	# Salgo de la funcion

finalizar_decode_ok:
	li v0, 0
	sw v0,48(sp)      # guardo valor return en v0
	b E_FIN

finalizar_decode_error_read:
	li v0, 1
	sw v0,48(sp)      # guardo valor return en v0
	b E_FIN

finalizar_decode_error_write:
	li v0, 2
	sw v0,48(sp)      # guardo valor return en v0
	b E_FIN


.end decode

.ent	f

f:
        .frame  $fp,48,ra
        .set    noreorder
        .cpload t9
        .set    reorder
        subu    sp,sp,48
        .cprestore 40           #    REGISTER SAVE AREA
                                # 44| ////PADDING//// |
        sw      ra,48(sp)     	# 40|       $ra       |
        sw      $fp,44(sp)     # 36|       $fp       |

        move    $fp,sp
        sw      a0,36(sp)	# a0: infd
        sw      a1,32(sp)	# a1: outfd
        sw      a2,28(sp)	# a2: indice_par_hexa
        sw      a3,16(sp)	# a3: par_hexa
F_WHILE:
	lw	a0,36(sp)	# a0 = infd
	la	a1,12(sp)	# a1 = dir de mem donde voy a leer
	li	a2,1		# a2 = 1 (cantidad de bytes a leer)
	li	v0, SYS_read	# Cargo syscall
	syscall			# Ejecuto syscall

	#################################
	bltz	v0, error_read_decode 	# Terminar si error
	#################################
	#################################
	beq	v0, 0, finalizar_F_ok 			# Terminar si no leo la cantidad pedida (< 1)
	#################################


F_DO:
        lw      t0,16(sp)      # par_hexa (array base)
        lw      t1,28(sp)      # [indice_par_hexa] (array offset)
        addu    t0,t0,t1        # par_hexa[indice_par_hexa]
        lbu     t1,12(sp)      # leo c de memoria
        sb      t1,0(t0)        # par_hexa[....] = c

        lw      a0,28(sp)      # a0 = indice_par_hexa
        lw      a1,16(sp)	# a1 = par_hexa
        lw      a2,32(sp)	# a2 = outfd
        la      t9,g           # Cargo direccion de g
        jal     ra,t9         # Llamo a g(a0,a1,a2)
        sw      v0,28(sp)      # Guardo indice_par_hexa para el return

	#################################
	beq	v0, -2, F_FIN 	# Terminar si error en write
	#################################

        b       F_WHILE

F_FIN:

        lw      v0,28(sp)
	lw      gp,40(sp)     	# Recupero gp
        lw      ra,48(sp)
        lw      $fp,44(sp)
        addu    sp,sp,48
        j       ra
        .end    f

#################################
error_read_decode:
	li v0, -1
	sw      v0,28(sp)      # guardo valor return en v0	
	b F_FIN 
#################################

#################################
finalizar_F_ok:
	li v0, 0
	sw v0,28(sp)      # guardo valor return en v0
	b F_FIN
#################################

.ent	g
g:
        .frame  $fp,40,ra
        .set    noreorder
        .cpload t9
        .set    reorder
        subu    sp,sp,40      # CREO EL STACK FRAME DE 40 BYTES
        .cprestore 32
                                #    SAVE REGISTER AREA
                                # 36 | ////PADDING//// |
        sw      ra,40(sp)     	# 32 |      $ra        |
        sw      $fp,36(sp)     	# 28 |      $fp        |
        move    $fp,sp

        sw      a0,28(sp)     	# indice_par_hexa
        sw      a1,24(sp)     	# par_hexa
        sw      a2,20(sp)     	# outfd

        lw      t1,28(sp)	# Cargo indice_par_hexa
        li      t2,1		# Cargo 1
        bne     t1,t2,ELSE	# if (indice_par_hexa != 1) => ELSE

        subu    t1,t1,1		# --indice_par_hexa
        sw      t1,16(sp)	# lo guardo

        la      t9,h           # h(...)
        lw      t3,24(sp)     	#  (par_hexa)
	la	a0,0(t3)
        jal     ra,t9
        sb      v0,12(sp)	# Guardo uint8_t valor_binario

	lw	a0,20(sp)	# a0 =  outfd
	la	a1,12(sp)	# a1 = &valor_binario
	li	a2,1		# a2 = 1 (cantidad a escribir)
	li	v0,SYS_write	# Cargo el syscall
	syscall			# Ejecuto el syscall

	#################################
	bltz	v0, error_write_decode 	# Terminar si no escribo la cantidad pedida (< 1)
	#################################

        b       FIN
ELSE:
        lw      t1,28(sp)	# Carga valor original
        addu    t1,t1,1		# indice par hexa ++
        sw      t1,16(sp)	# Guardo indice par hexa  

	
FIN:
        lw      v0,16(sp)	# Devuelvo indice par hexa
        lw      ra,40(sp)
        lw      $fp,36(sp)
        lw      gp,32(sp)
        addu    sp,sp,40
        j       ra

#################################
error_write_decode:
	li v0, -2
	sw v0,16(sp)	
	b FIN
#################################	

.end    g

.ent	h
h:
	.frame $fp, 32, ra
	.set noreorder
	.cpload t9
	.set reorder

	#cargo stack frame...
	subu sp, sp, 32

	# Save Register Area
	.cprestore 20 
	sw ra, 28(sp)
	sw $fp, 24(sp)
	move $fp, sp


	lb t0, 0(a0)            #t0=vector[0]
	lb t1, 1(a0)            #t1=vector[1]
	addi t2,zero,48         #carga char '0'
	subu t0,t0,t2           #t0=t0-'0'
	subu t1,t1,t2           #t1=t1-'0'
	addi t3, zero, 49
	blt t1, t3,else_if_1    #if t1 < 49 then else_if_1
	addi t1,t1,-39          #t1=t1-39
	j if_2

else_if_1:
    addi t4,zero,17
    blt t1,t4, if_2         #if t1 < t4 then if_2
    addi t1,t1,-7           #t1=t1-7
    j if_2

if_2:
   blt t0,t3,else_if_2      #if t0 < 49 then else_if_2
   addi t0,t0,-39           #to=to-39
   j else_if_2

else_if_2:
   sll t0,t0,4              #t0=to << 4
   or t0,t0,t1              #t0=t0 | t1
   move v0,t0
   b finalizar_h

finalizar_h:
	move sp, $fp	
	lw $fp, 24(sp) # frame pointer
	lw gp, 20(sp) # global pointer
	lw ra, 28(sp)   # levanto return address
	addu sp,sp,32 # destruyo stack frame
	j ra
.end    h

.rdata
.align 0
vector: .word '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
